<?php
/**
 * @class twitter
 * @abstract Used to call the Twitter API methods
 * @author Simon Fletcher <simon@youmeo.com>
 * @version 1.0
 */
class twitter {

	public $authenticated = false;
	public $format = 'xml';
	public $debug = false;
	
	protected $curl;
	protected $curl_return;
	protected $curl_info;
	
	/**
	 * @method __construct
	 * @visibility public
	 * @abstract Used to initialize the cURL object
	 */
	public function __construct() {
		
		/**
		 * Initialize cURL object
		 */
		$this->curl = @curl_init(  );

		if( is_resource( $this->curl ) !== ( true ) ) {

			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_NOCURL ], TWTR_Exception_Codes::TWTR_NOCURL );
		
		}
		
		/**
		 * Setup required cURL parameters
		 */
		$this->load_params(  );
		
		/**
		 * Define the Twitter API constants
		 */
		define( 'REST_URL', 'http://twitter.com' );
		define( 'AUTH_ERRORSTRING', 'not authenticate' );
	
	}
	
	/**
	 * @method load_params
	 * @visibility private
	 * @abstract Sets up the required cURL parameters
	 */
	private function load_params() {
	
		$params = array(
		
			CURLOPT_RETURNTRANSFER => ( true ),
			CURLOPT_FOLLOWLOCATION => ( true ),
			CURLOPT_USERAGENT => $_SERVER[ 'HTTP_USER_AGENT' ]
		
		);

		if( $this->debug !== ( false ) ) {

			$params[ CURLOPT_HEADER ] = ( true );
		
		} else {
		
			$params[ CURLOPT_HEADER ] = ( false );
		
		}
				
		foreach( $params as $k => $v ) {
		
			$this->add_param( $k, $v );
		
		}
			
	}
	
	/**
	 * @method add_param
	 * @visibility protected
	 * @abstract Add cURL parameter
	 * @param parameter	String			-	the parameter to set
	 * @param value		String/Boolean	-	the value to set
	 * @result Boolean	-	True
	 */
	public function add_param( $parameter, $value ) {
	
		if( curl_setopt( $this->curl, $parameter, $value ) !== ( false ) ) {
			
			return ( true );
		
		} else {
		
			return ( false );
		
		}
	
	}
	
	/**
	 * @method authenticate_request
	 * @visibility public
	 * @abstract Authenticates Twitter API calls
	 * @param username	string	-	the username to authenticate requests with
	 * @param password	string	-	the password to authenticate requests with
	 * @result Boolean	-	True if the authentication was accepted or false if it was denied
	 */
	public function authenticate_request( $username, $password ) {
	
		$this->add_param( CURLOPT_USERPWD, ( $username . ':' . $password ) );
		
		if( $this->call_method( 'account', 'verify_credentials' ) !== ( false ) ) {
		
			$this->authenticated = ( true );
			
			return ( true );
		
		}
	
	}
	
	/**
	 * @method construct_url
	 * @visiblity protected
	 * @abstract Constructs the URL for the class to call via cURL
	 * @param object	string	-	the object to call
	 * @param method	string	-	the method to call
	 * @param get		string	-	the extra GET parameters to append on the URL
	 * @result String	-	The constructed URL
	 */
	protected function construct_url( $object, $method, $get = '' ) {

		$amp = '?';
		
		if( is_array( $get ) !== ( false ) ) {
			
			foreach( $get as $k => $v ) {
				
				if( empty( $v ) !== ( true ) ) {
					
					$_get .= $amp . urlencode( $k ) . '=' . urlencode( $v );
					$amp = '&';
				
				}
								
			}
		
		}
				
		$url = REST_URL . '/' . $object . '/' . $method . '.' . $this->format . $_get;
		
		return ( $url );
	
	}
	
	/**
	 * @method parse_result
	 * @visibility protected
	 * @abstract Parses the XML response into strings
	 * @param result	string	-	the XML response
	 * @response Array	-	an array of XML strings
	 */
	protected function parse_result( $result ) {
	
		if( $this->format === 'xml' ) {
		
			if( function_exists( 'simplexml_load_string' ) ) {
			
				$xml = simplexml_load_string( $result );                          
			
			} else {
			
				throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_SIMPXML ], TWTR_Exception_Codes::TWTR_SIMPXML );
			
			}
			
			return $xml;
		
		} else if( $this->format === 'json' ) {
		
			return json_decode( $result );
		
		} else {
		
				throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_NOFORM ], TWTR_Exception_Codes::TWTR_NOFORM );
		
		}
	
	}
	
	/**
	 * @method call_method
	 * @visibility public
	 * @abstract Using the cURL extension the method calls the Twitter API
	 * @param object	string	- the object being called
	 * @param method	string	-  the method being called
	 * @param params	array	- the extra parameters being sent
	 * @result String		-	if the call was successfull the text result is returned
	 * @result Exception	-	if the call was unsuccessfull the method throws an exception
	 */
	public function call_method( $object, $method, Array $params = array() ) {
	
		$url = $this->construct_url( $object, $method, $params[ 'get' ] );
	
		$this->add_param( CURLOPT_URL, $url );

		if( is_array( $params[ 'post' ] ) !== ( false ) ) {
	
			$amp = '';
			
			foreach( $params[ 'post' ] as $k => $v ) {
				
				$post .= $amp . $k . '=' . $v;
				$amp = '&';
			
			}		
			
			$this->add_param( CURLOPT_POST, ( true ) );
			$this->add_param( CURLOPT_POSTFIELDS, $post );
		
		}
			
		$this->curl_return	= curl_exec( $this->curl );
		$this->curl_info	= curl_getinfo( $this->curl );
				
		if( $this->debug !== ( false ) ) {
		
			echo '<pre>' . $this->curl_return . '</pre>';
			exit;
		
		}
								
		if( intval( $this->curl_info[ 'http_code' ] ) != 200 ) {
		
			$response = $this->parse_result( $this->curl_return );

			if( eregi( AUTH_ERRORSTRING, $response->error ) !== ( false ) ) {
			
				throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_AUTH ], TWTR_Exception_Codes::TWTR_AUTH );
			
			} else {
			
				throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_APIERROR ], TWTR_Exception_Codes::TWTR_APIERROR );
			
			}
			
		} else {

			$response = $this->parse_result( $this->curl_return );
		
			return ( $response );
		
		}
	
	}

}

/**
 * @class phpTweet
 * @abstract The class which contains the different Twitter API methods
 */
class phpTweet extends twitter {

	public function __construct(){
	
		parent::__construct();
	
	}
	
	public function authenticate_request( $username, $password ) {
	
		if( empty( $username ) !== ( true ) && empty( $password) !== ( true ) ) {
		
			if( parent::authenticate_request( $username, $password ) !== ( false ) ) {
			
				return ( true );
			
			}
			
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_EMPCRED ], TWTR_Exception_Codes::TWTR_EMPCRED );
		
		}
	
	}
	
	public function public_timeline( ) {

		$results = parent::call_method( 'statuses', 'public_timeline' );
		
		return ( $results );
	
	}
	
	public function friends_timeline( $since = '', $since_id = '', $count = '', $page = '' ) {
		
		$params[ 'since' ] = $since;
		$params[ 'since_id' ] = $since_id;
		$params[ 'count' ] = $count;
		$params[ 'page' ] = $page;
			
		$results = parent::call_method( 'statuses', 'friends_timeline', array( 'get' => $params )  );
		
		return ( $results );
	
	}
	
	public function user_timeline( $id = '', $since = '', $since_id = '', $count = '', $page = '' ) {

		$url = 'user_timeline';
		
		if( empty( $id ) !== ( true ) ) {
		
			$url .= '/' . urlencode( $id );
		
		}
		
		$params[ 'since' ] = $since;
		$params[ 'since_id' ] = $since_id;
		$params[ 'count' ] = $count;
		$params[ 'page' ] = $page;
			
		$results = parent::call_method( 'statuses', $url, array( 'get' => $params )  );
		
		return ( $results );
	
	}

	public function statuses_show( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'statuses', 'show/' . $id  );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}

	public function update( $status, $reply = false ) {
	
		if( empty( $status ) !== ( true ) ) {
		
			$post[ 'status' ] = urlencode( $status );
			
			if( $reply !== ( false ) && is_numeric( $reply ) !== ( false ) ) {
				
				$post[ 'in_reply_to_status_id' ] = $reply;
			
			}

			$results = parent::call_method( 'statuses', 'update', array( 'post' => $post )  );
		
			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_STATUS ], TWTR_Exception_Codes::TWTR_STATUS );
		
		}
		
	}

	public function replies( $page = '', $since = '', $since_id = '' ) {

		$params[ 'page' ]		= $page;
		$params[ 'since' ]		= $since;
		$params[ 'since_id' ]	= $since_id;
			
		$results = parent::call_method( 'statuses', 'replies', array( 'get' => $params )  );
		
		return ( $results );
	
	}

	public function destroy( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'statuses', 'destroy/' . $id, array( 'post' => array( 'id' => $id ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}
	
	public function friends( $username = '', $page = '' ) {
	
		$url = 'friends';
		
		if( empty( $username ) !== ( true ) ) {
		
			$url .= '/' . urlencode( $username );
		
		}
		
		$results = parent::call_method( 'statuses', $url, array( 'get' => array( 'page' => $page ) )  );
		
		return ( $results );
	
	}	
	
	public function followers( $id = '', $page = '' ) {
	
		$url = 'followers';
		
		if( empty( $username ) !== ( true ) ) {
		
			$url .= '/' . urlencode( $username );
		
		}
		
		$results = parent::call_method( 'statuses', $url, array( 'get' => array( 'page' => $page ) )  );
		
		return ( $results );
	
	}	
	
	public function users_show( $id = '', $page = '', $screen_name = '' ) {
	
		$url = 'show';
		
		if( empty( $username ) !== ( true ) ) {
		
			$url .= '/' . urlencode( $username );
		
		}
		
		$results = parent::call_method( 'users', $url, array( 'get' => array( 'page' => $page, 'screen_name' => $screen_name ) )  );
		
		return ( $results );
	
	}	
	
	public function direct_messages( $since = '', $since_id = '', $page = '' ) {
	
		$get[ 'since' ]		= $since;
		$get[ 'since_id' ]	= $since_id;
		$get[ 'page' ]		= $page;
		
		$results = parent::call_method( '', 'direct_messages', array( 'get' => $get )  );
		
		return ( $results );
	
	}	
	
	public function sent( $since = '', $since_id = '', $page = '' ) {
	
		$get[ 'since' ]		= $since;
		$get[ 'since_id' ]	= $since_id;
		$get[ 'page' ]		= $page;
		
		$results = parent::call_method( 'direct_messages', 'sent', array( 'get' => $get )  );
		
		return ( $results );
	
	}
	
	public function direct_messages_new( $user, $text ) {
	
		if( empty( $user ) !== ( true ) && empty( $text ) !== ( true ) ) {
				
			$results = parent::call_method( 'direct_messages', 'new', array( 'post' => array( 'user' => $user, 'text' => $text ) )  );
			
			return ( $results );
			
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_NEWMISS ], TWTR_Exception_Codes::TWTR_NEWMISS );
		
		}
	
	}

	public function direct_messages_destroy( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'direct_messages', 'destroy/' . $id, array( 'post' => array( 'id' => $id ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}

	public function create( $id, $follow = '' ) {
	
		if( is_numeric( $id ) !== ( false ) ) {
		
			$results = parent::call_method( 'direct_messages', 'friendships/' . $id, array( 'post' => array( 'follow' => $follow ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}
	
	public function friendships_create( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'friendships', 'destroy/' . $id, array( 'post' => array( 'id' => $id ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}
	
	public function exists( $id, $id2 ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) && is_numeric( $id2 ) !== ( false ) && empty( $id2 ) !== ( true ) ) {
		
			$results = parent::call_method( 'friendships', 'exists', array( 'get' => array( 'user_a' => $id, 'user_b' => $id2 ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}

	public function friends_ids( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'friends', 'ids', array( 'get' => array( 'id' => $id ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}

	public function followers_ids( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'followers', 'ids', array( 'get' => array( 'id' => $id ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}

	public function verify_credentials( ) {
	
		$results = parent::call_method( 'account', 'verify_credentials' );

		return ( $results );
			
	}

	public function end_session( ) {
	
		$results = parent::call_method( 'account', 'end_session' );

		return ( $results );
			
	}	
	
	public function update_delivery_device( $device ) {
	
		$allowed = array(
		
							'sms',
							'im',
							'none'
		
		);
	
		if( empty( $service ) !== ( true ) && in_array( $deice, $allowed ) !== ( false ) ) {
		
			$results = parent::call_method( 'account', 'update_delivery_device', array( 'post' => array( 'device' => $device ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISPARA ], TWTR_Exception_Codes::TWTR_MISSPARA );
		
		}
			
	}

	public function update_profile_colors( $profile_background_color = '', $profile_text_color = '', $profile_link_color = '', $profile_sidebar_fill_color = '', $profile_sidebar_border_color = '' ) {

		$post[ 'profile_background_color' ] 	= $profile_background_color;
		$post[ 'profile_text_color' ]			= $profile_text_color;
		$post[ 'profile_link_color' ]			= $profile_link_color;
		$post[ 'profile_sidebar_fill_color' ]	= $profile_sidebar_fill_color;
		$post[ 'profile_sidebar_border_color' ]	= $profile_sidebar_border_color;

		$results = parent::call_method( 'account', 'update_profile_colors', array( 'post' => $post ) );

		return ( $results );
	
	}

	public function update_profile_image( $image ) {
	
		$types = array(
		
						IMAGETYPE_GIF,
						IMAGETYPE_JPEG,
						IMAGETYPE_PNG
		
		);
	
		if( empty( $image ) !== ( true ) && in_array( exif_imagetype( $image ), $types ) !== ( false ) ) {
		
			$results = parent::call_method( 'account', 'update_profile_image', array( 'post' => array( 'image' => $image ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_NOIMG ], TWTR_Exception_Codes::TWTR_NOIMG );
		
		}
			
	}

	public function update_profile_background_image( $image ) {
	
		$types = array(
		
						IMAGETYPE_GIF,
						IMAGETYPE_JPEG,
						IMAGETYPE_PNG
		
		);
	
		if( empty( $image ) !== ( true ) && in_array( exif_imagetype( $image ), $types ) !== ( false ) ) {
		
			$results = parent::call_method( 'account', 'update_profile_background_image', array( 'post' => array( 'image' => $image ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_NOIMG ], TWTR_Exception_Codes::TWTR_NOIMG );
		
		}
			
	}

	public function rate_limit_status(  ) {

		$results = parent::call_method( 'account', 'rate_limit_status' );
		
		return ( $results );
	
	}

	public function update_profile( $name = '', $email = '', $url = '', $location = '', $description = '' ) {

		$post[ 'name' ]			= $name;
		$post[ 'email' ]		= $email;
		$post[ 'url' ]			= $url;
		$post[ 'location' ]		= $location;
		$post[ 'description' ]	= $description;

		$results = parent::call_method( 'account', 'update_profile', array( 'post' => $post ) );

		return ( $results );
	
	}

	public function favorites( $id = '', $page = '' ) {
	
		$url = 'favourites';
		
		if( empty( $username ) !== ( true ) ) {
		
			$url .= '/' . urlencode( $username );
		
		}
		
		$results = parent::call_method( '', $url, array( 'get' => array( 'page' => $page ) )  );
		
		return ( $results );
	
	}	

	public function favourites_create( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'favourites', 'create/' . $id, array( 'post' => array( 'id' => $id ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}

	public function favourites_destroy( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'favourites', 'destroy/' . $id, array( 'post' => array( 'id' => $id ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}

	public function follow( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'notifications', 'follow/' . $id, array( 'post' => array( 'id' => $id ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}

	public function leave( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'notifications', 'leave/' . $id, array( 'post' => array( 'id' => $id ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}

	public function blocks_create( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'blocks', 'create/' . $id, array( 'post' => array( 'id' => $id ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}

	public function blocks_destroy( $id ) {
	
		if( is_numeric( $id ) !== ( false ) && empty( $id ) !== ( true ) ) {
		
			$results = parent::call_method( 'blocks', 'destroy/' . $id, array( 'post' => array( 'id' => $id ) ) );

			return ( $results );
		
		} else {
		
			throw new TWTR_Exception( TWTR_Exception_Codes::$error_desc[ TWTR_Exception_Codes::TWTR_MISSID ], TWTR_Exception_Codes::TWTR_MISSID );
		
		}
			
	}

	public function help(  ) {

		$results = parent::call_method( 'help', 'test' );
		
		return ( $results );
	
	}
															
}

class TWTR_Exception extends Exception {
}

class TWTR_Exception_Codes extends TWTR_Exception {

	const TWTR_NOCURL	= 0;
	const TWTR_AUTH		= 1;
	const TWTR_APIERROR	= 2;
	const TWTR_SIMPXML	= 3;
	const TWTR_NOFORM	= 4;
	const TWTR_EMPCRED	= 5;
	const TWTR_MISSID	= 6;
	const TWTR_STATUS	= 7;
	const TWTR_NEWMISS	= 8;
	const TWTR_MISSPARA	= 9;
	const TWTR_NOIMG	= 10;
	
	public static $error_desc = array(
	
		0	=> 'cURL is required to use phpTweet',
		1	=> 'You are not authorized for this action, please call phpTweet::authenticate_request( $user, $pass ). If you _ARE_ calling phpTweet::authenticate_request() this error means the credentials provided are incorrect',
		2	=> 'Twitter API call failed',
		3	=> 'You must have SimpleXML installed to use the XML format',
		4	=> 'No accepted format has been used. Please use either XML or JSON',
		5	=> 'You must provide both a username and a password when calling phpTweet::authenticate_request()',
		6	=> 'You are missing the ID parameter. Please specify it as an argument when calling the method (phpTweet::method( 234 );)',
		7	=> 'Please specify the status to update the account with using the method\'s argument list',
		8	=> 'Please specify a user to send the DM to and the message to send with it using the method\'s arguments list',
		9	=> 'You are missing a parameter in the method\'s arugment list. Please check the documentation within the class',
		10	=> 'You must provide a valid image (must be a GIF, PNG or JP(e)G',
		
	);

}